﻿/******************************************************************************
*  COPYRIGHT MorningCore CO.,LTD
******************************************************************************/

/*----------- function definition-----------------------------------*/
/*****************************************************************************
* Function: SRP_PUSCH_FE_ParamGen()
* Purpose:  This function performs pusch's modulation
*
* Relation:
Calls       : ....
Called by   : ....
* Params:
*   <Name>          <Type>      <In/Out>    <Description>

* Return:  void
* Note:    <no>
*******************************************************************************/
#include "../head/ue_tx_pusch_paramgen_f.h"
#include "../head/Ue_Tx_FilePrintf.h"
#include "../head/wx_ul_commom_param.h"

//#define _CRT_SECURE_NO_DEPRECATE
/******************************************************************************
*  INCLUDE FILES
******************************************************************************/
void SRP_PUSCH_FE_ParamGen(stULParamTable *SimParam)
{
	/*variables definition*/
	int8	i; // for cycle
	int8	AlphaSeq[3];
	int16	Temp = 0;			// temporary value
	int8    LayerNum = SimParam->Fixed_RI;
	int     DMRSReNum_allUE,Qm,NL,NLxQm,SCH_RE;
	float   N_info;
	UINT32  uwTBLen;
	UINT32     CodeBlkNum[1] = {0};
	UINT32     TBLenAddAllCrc[1] = {0};
	UINT32	   CodeBlkLen = 0;
	int    CDM_Group_Flag[3] = {0,0,0}; 

	/*Init*/
	if((SimParam->Start_n_TTI == SimParam->iTTI)&&(SimParam->iUe==0))
	{
		g_ulSeed_ldpc=0; // 每次仿真的Start_n_TTI位置重新初始化ldpc数据源的随机种子
	}

    /*Function body*/
    // 查表配置的参数
    // calc SimParam->RB_BitMap[MAXRBNUM]: 1 - Data RB, 0 - NULL RB
    RB_BitMapCalc(SimParam);

    if ((SimParam->PUSCH_HARQ_Flag == 1) || (SimParam->PUSCH_CSI1_Flag == 1))
    {
        SimParam->PUSCHMultiFlag = 1;
    }
    else
    {
        SimParam->PUSCHMultiFlag = 0;
    }

	// cal SimParam->u8_DMRS_Pos to indicator the symbol is PUSCH or DMRS
	SymMapCalc(SimParam);

    /* DMRS front located symbol mapping */
    DMRSReNum_allUE = SC_PER_RB * SimParam->PUSCH_RB_Num; // DFT don't support DMRS_SCH_Combin
    SimParam->DMRS_SCH_Combin = 0; //dmrs ofdm symbol =  [dmrs re for iUe]
    SimParam->PUSCH_DMRS_Beta = 1.4125;
    SimParam->PUSCH_Data_SymNum = SimParam->PUSCH_SymNum - SimParam->DMRS_NumInOneSlot; // used for PUSCH_TransPrecoding_f

    // pusch re number = ALLRE - DMRSRE
    SimParam->PUSCH_RE_Num = SimParam->PUSCH_RB_Num * SimParam->PUSCH_SymNum * SC_PER_RB - (SimParam->DMRS_NumInOneSlot * DMRSReNum_allUE);
    SimParam->PUSCH_UCI_RE_Num = SimParam->PUSCH_RB_Num * (SimParam->PUSCH_SymNum - SimParam->DMRS_NumInOneSlot) * SC_PER_RB; // 去掉DMRS占的RE

	// calc PTRS param, position of ptrs 
	if (SimParam->UL_PTRS_present == 1)
	{
		PTRS_ParaGen(SimParam);
		SimParam->PUSCH_UCI_RE_Num = SimParam->PUSCH_UCI_RE_Num - SimParam->PTRS_RE_Num*SimParam->PTRS_Symb_Num; // 去掉PTRS占的RE
	}

    // layer number of every Codeword
    SimParam->LayerNumOf1cw[0] = 1;
    SimParam->LayerNumOf1cw[1] = 0;

    // PUSCH_BitLen for every Codeword
    for (i = 0; i < SimParam->CwNum; i++)
	{ 
		Qm = SimParam->ModuMod[i] > 0 ? (SimParam->ModuMod[i] * 2) : 1;

        NL = SimParam->LayerNumOf1cw[i];
        NLxQm = NL * Qm;
		if (SimParam->UL_PTRS_present == 0)
		{
			SimParam->QAM_SymNum[i] = SimParam->PUSCH_RE_Num * NL;
		}
		else
		{
			SimParam->QAM_SymNum[i] = (SimParam->PUSCH_RE_Num - SimParam->PTRS_RE_Num*SimParam->PTRS_Symb_Num) * NL; // RM delete PTRS RE
		}

        SimParam->PUSCH_BitLen[i] = Qm * SimParam->QAM_SymNum[i];
        //
        SCH_RE = SimParam->PUSCH_RE_Num  - SimParam->PUSCH_Xoh_PerPRB * SimParam->PUSCH_RB_Num; //AllRE - DMRSRE - XohRE
		SimParam->PUSCHData_BitLen_ForTBS[i] = min(144 * SimParam->PUSCH_RB_Num, SCH_RE) * NLxQm;

        N_info = (float)(SimParam->PUSCHData_BitLen_ForTBS[i]) * SimParam->fRate[i]; //每个PRB内最大的RE数不能超过156
        uwTBLen = vGetTBS_cal(N_info, SimParam->fRate[i], CodeBlkNum, TBLenAddAllCrc);
		if (SimParam->ucReTxFlag[i] > 0)
		{
			uwTBLen = stReTxParaVar.auwReTranTBS[SimParam->iUe][SimParam->ucHarqIdx[i]];
			CodeBlkNum[0] = stReTxParaVar.aucCodeBlkNum[SimParam->iUe][SimParam->ucHarqIdx[i]];
			TBLenAddAllCrc[0] = uwTBLen + (CodeBlkNum[0] == 1 ? 0 : CodeBlkNum[0] * 24) + (uwTBLen <= 3824 ? 16 : 24);
		}
        CodeBlkLen = vGet_Kr_cal(uwTBLen, CodeBlkNum[0], TBLenAddAllCrc[0], SimParam->fRate[i]);
        SimParam->PUSCH_SCH_B_Len[i] = CodeBlkNum[0] * CodeBlkLen;
        SimParam->P_CiniForScram[i] = ((SimParam->RNTI << 15) + SimParam->N_CELL_ID) + (i << 13);   //calculate the C init over
    }
    // Slot index
    SimParam->SlotIdx = SimParam->iTTI % (10 * SimParam->SCS[SimParam->UeScsIdx] / 15); //calculate the C init over
	SimParam->k2_shift =  - SimParam->CHBW*6;  //FTT模块k2搬移参数

    // calc DMRS Gen para: u, v
    DMRS_Gen_ParaCalc(SimParam);

	// calc rate match output length of ack , csi1 , csi2
    Pusch_RateMatch(SimParam); //暂时只支持单个码字

    // calc params when HopMod is enable
    Pusch_RateMatch_HopEn(SimParam); //暂时只支持单个码字

    //caculate position of pusch、dmrs、ack、csi、ptrs
    pusch_re_pattern(SimParam);
   
    Temp = SimParam->PUSCH_RB_Num * SC_PER_RB;

    // 2^AlphaSeq[2]*3^AlphaSeq[1]*5^AlphaSeq[0] = PUSCH_RB_Num*SC_PER_RB
    Alpha_DFT_Calc(Temp, AlphaSeq);

    SimParam->P_Alpha2 = AlphaSeq[2];
    SimParam->P_Alpha3 = AlphaSeq[1];
    SimParam->P_Alpha5 = AlphaSeq[0];

	if (SimParam->SRS_EnFlag == 0)
	{
		PhaseCompensation_para_gen(SimParam);//相位补偿模块
		TimeDomainWindow_para_gen(SimParam);//窗系数生成模块
	}

    HybridDFT_para_gen(SimParam);
	BetaPuschCalcultion(SimParam);
	SRP_para_gen(SimParam);

}

void BetaPuschCalcultion(stULParamTable *SimParam)
{
	double BetaPUSCH1_r;
	int8 Ipflag =0;
	int BitLen = 14;
	double BetaPUSCH_FixFloatdiffTable[4] = {sqrt(2.0),sqrt(2.0),sqrt(10.0),sqrt(42.0)};
	int Delta1[4] = { 1,1,2,3 };

	BetaPUSCH1_r = BetaPUSCH_FixFloatdiffTable[SimParam->ModuMod[0]]; // 调制缩放
	BetaPUSCH1_r = BetaPUSCH1_r*sqrt(SimParam->PUSCH_RB_Num*12.0)/pow(2.0,SimParam->num_shift+ Delta1[SimParam->ModuMod[0]]); // 调制缩放+DFT缩放

    SimParam->float_fix_dif = BetaPUSCH1_r; // beta1

    BetaPUSCH1_r = BetaPUSCH1_r*(SimParam->PUSCH_DMRS_Beta/SimParam->PUSCH_Beta);
    SimParam->BetaDMRS = (fractM)(BetaPUSCH1_r*(1<<22));//定标为Q(27,5)

}

///=================================================================================================
// cal SimParam->u8_DMRS_Pos to indicator the symbol is PUSCH or DMRS
void SymMapCalc(stULParamTable *SimParam)
{
    uint8 u8_DMRS_Table_start = 0; // temp for getting additional DMRS start position
    uint16 u16_m = 0, u16_j = 0;
    char Fhopping_flag = SimParam->frequencyHoppFlag ; // 0 - no hopping, 1 - hopping
    char sym_per_hop1 = SimParam->PUSCH_SymNum / 2; // symbol number of first hop
    char sym_per_hop2 = SimParam->PUSCH_SymNum - SimParam->PUSCH_SymNum / 2; // symbol number of second hop

    //init output
    for (u16_m = 0; u16_m < RS_NUM_PER_TTI_UL; u16_m++)
    {
        SimParam->DMRS_SymIdx[u16_m] = 0;
    }

    for (u16_m = 0; u16_m < MAXSYMNUM; u16_m++)
    {
        SimParam->u8_DMRS_Pos[u16_m] = 255;
        SimParam->PUSCH_RB_Offset[u16_m] = 0; // init
    }

    for (u16_m = (UINT8)SimParam->PUSCH_Symb_Start; u16_m < (UINT8)SimParam->PUSCH_Symb_Start + SimParam->PUSCH_SymNum; u16_m++)
    {
        SimParam->u8_DMRS_Pos[u16_m] = 0; //PUSCH

        if ((Fhopping_flag == 1) && (SimParam->RA_Type == 1)) // intra-slot hop
        {
            if (u16_m < SimParam->PUSCH_Symb_Start + sym_per_hop1) // first hop
            {
                SimParam->PUSCH_RB_Offset[u16_m] = 0;
            }
            else // second hop
            {
                SimParam->PUSCH_RB_Offset[u16_m] = SimParam->PUSCH_VRB_Offset;
            }
        }
    }

	// 查表的起始列: 1-0, 2-1, 3-3
	if (SimParam->PUSCH_DMRS_Add_Pos < 3)
	{
		u8_DMRS_Table_start = SimParam->PUSCH_DMRS_Add_Pos - 1;
	}
	else
	{
		u8_DMRS_Table_start = 3;
	}

    // 1 - DMRS; 0 - PUSCH; 255 - No UL-Data
    // front DMRS or first hop
    SimParam->DMRS_SymIdx[0] = SimParam->PUSCH_DMRS_typeA_Pos; 
    SimParam->u8_DMRS_Pos[SimParam->PUSCH_DMRS_typeA_Pos] = 1;

    // additional DMRS
    if (Fhopping_flag == 0) // no hopping
    {
		SimParam->DMRS_NumInOneSlot = 1;

        if (SimParam->PUSCH_SymNum > 7) // SimParam->PUSCH_SymNum based 1
        {
            for (u16_m = 0; u16_m < SimParam->PUSCH_DMRS_Add_Pos; u16_m++)
            {
				SimParam->DMRS_SymIdx[u16_m + 1] = DMRS_Add_Pos_OneSymb[SimParam->PUSCH_SymNum - 8][u8_DMRS_Table_start + u16_m];
				if (SimParam->DMRS_SymIdx[u16_m + 1] > 0)
				{
					// DMRS symbol number
					SimParam->u8_DMRS_Pos[DMRS_Add_Pos_OneSymb[SimParam->PUSCH_SymNum - 8][u8_DMRS_Table_start + u16_m]] = 1;
					SimParam->DMRS_NumInOneSlot = SimParam->DMRS_NumInOneSlot + 1;
				}
            }
        }
    }
    else // hopping
    {
        //second hop, DMRS_SymIdx = 1
        if ((sym_per_hop2 >= 4) && (sym_per_hop2 <= 7))
        {
            SimParam->u8_DMRS_Pos[sym_per_hop1 + SimParam->PUSCH_Symb_Start] = 1;
            SimParam->DMRS_SymIdx[1] = sym_per_hop1 + SimParam->PUSCH_Symb_Start;
        }

		SimParam->DMRS_NumInOneSlot = 2; // first hop, second hop

        // PUSCH_DMRS_Add_Pos == 1
        if (SimParam->PUSCH_DMRS_Add_Pos == 1)
        {
            if (SimParam->PUSCH_SymNum > 8) // SimParam->PUSCH_SymNum/2 >= 5
            {
                // second hop 0+4, DMRS_SymIdx = 2
                SimParam->u8_DMRS_Pos[sym_per_hop1 + SimParam->PUSCH_Symb_Start + 4] = 1;
                SimParam->DMRS_SymIdx[2] = sym_per_hop1 + SimParam->PUSCH_Symb_Start + 4;
				SimParam->DMRS_NumInOneSlot = 3; // 1 in first hop, 2 in second hop
            }

            if ((sym_per_hop1 == 7) && (SimParam->PUSCH_DMRS_typeA_Pos == 2)) // SimParam->PUSCH_SymNum/2 == 7
            {
                // first hop, l0+4, DMRS_SymIdx = 1
                SimParam->u8_DMRS_Pos[SimParam->PUSCH_DMRS_typeA_Pos + 4] = 1;
                SimParam->DMRS_SymIdx[1] = SimParam->PUSCH_DMRS_typeA_Pos + 4;
                // second hop 0, DMRS_SymIdx = 2
                SimParam->u8_DMRS_Pos[sym_per_hop1] = 1;
                SimParam->DMRS_SymIdx[2] = sym_per_hop1;
                // second hop 0+4, DMRS_SymIdx = 3
                SimParam->u8_DMRS_Pos[sym_per_hop1 + 4] = 1;
                SimParam->DMRS_SymIdx[3] = sym_per_hop1 + 4;
				SimParam->DMRS_NumInOneSlot = 4;  // 2 in first hop, 2 in second hop
            }
        }
    }
}

// cal PUSCH DMRS Gen Para
void DMRS_Gen_ParaCalc(stULParamTable *SimParam)
{
    int u16_m, m = 0;
    int   f_gh;         // f_gh, in 3GPP 38.211
    char  P_Seq_Op[35840];           // random sequence
    int   temp = 0;                 // for P_Seq_Op Generation
    uint32    N_ID_RS = 0;              // for P_Seq_Op Generation
    int PrimTable_dmrs_Delta1[273] = { 5,   11,   17,   23,   29,   31,   41,   47,   53,   59,  // 1~10
                                       61,   71,   73,   83,   89,   89,  101,  107,  113,  113,  // 11~20
                                       113,  131,  137,  139,  149,  151,  157,  167,  173,  179,  // 21~30
                                       181,  191,  197,  199,  199,  211,  211,  227,  233,  239,  // 31~40
                                       241,  251,  257,  263,  269,  271,  281,  283,  293,  293,  // 41~50
                                       293,  311,  317,  317,  317,  331,  337,  347,  353,  359,  // 51~60
                                       359,  367,  373,  383,  389,  389,  401,  401,  409,  419,  // 61~70
                                       421,  431,  433,  443,  449,  449,  461,  467,  467,  479,  // 71~80
                                       479,  491,  491,  503,  509,  509,  521,  523,  523,  523,  // 81~90
                                       541,  547,  557,  563,  569,  571,  577,  587,  593,  599,  // 91~100
                                       601,  607,  617,  619,  619,  631,  641,  647,  653,  659,  // 101~110
                                       661,  661,  677,  683,  683,  691,  701,  701,  709,  719,  // 111~120
                                       719,  727,  733,  743,  743,  751,  761,  761,  773,  773,  // 121~130
                                       773,  787,  797,  797,  809,  811,  821,  827,  829,  839,  // 131~140
                                       839,  839,  857,  863,  863,  863,  881,  887,  887,  887,  // 141~150
                                       887,  911,  911,  919,  929,  929,  941,  947,  953,  953,  // 151~160
                                       953,  971,  977,  983,  983,  991,  997,  997, 1013, 1019,  // 161~170
                                       1021, 1031, 1033, 1039, 1049, 1051, 1061, 1063, 1069, 1069,  // 171~180
                                       1069, 1091, 1097, 1103, 1109, 1109, 1117, 1123, 1129, 1129,  // 181~190
                                       1129, 1151, 1153, 1163, 1163, 1171, 1181, 1187, 1193, 1193,  // 191~200
                                       1201, 1201, 1217, 1223, 1229, 1231, 1237, 1237, 1249, 1259,  // 201~210
                                       1259, 1259, 1277, 1283, 1289, 1291, 1301, 1307, 1307, 1319,  // 211~220
                                       1321, 1327, 1327, 1327, 1327, 1327, 1361, 1367, 1373, 1373,  // 221~230
                                       1381, 1381, 1381, 1399, 1409, 1409, 1409, 1427, 1433, 1439,  // 231~240
                                       1439, 1451, 1453, 1459, 1459, 1471, 1481, 1487, 1493, 1499,  // 241~250
                                       1499, 1511, 1511, 1523, 1523, 1531, 1531, 1543, 1553, 1559,  // 251~260
                                       1559, 1571, 1571, 1583, 1583, 1583, 1601, 1607, 1613, 1619, 1621, 1627, 1637
                                     }; // 261~273
    float RootSeqParamTemp = 0;
    int start_pos = SimParam->SCS_Start[SimParam->UeScsIdx] * ((SimParam->PUSCH_DMRS_Group == PUSCH_DMRS_Type1) ? 6 : 4);
    int uIdx = 0, vIdx = 0;
    int   N_Symb_Slot = 0;
    uint32  x1 = 0, x2 = 0; //used in the Pseudo-random sequence generation
    uint32 uwCInit = 0;

    // N_ID_RS
    if (1 == SimParam->PUSCH_ID_En)
    {
        N_ID_RS = SimParam->N_PUSCH_ID;
    }
    else
    {
        N_ID_RS = SimParam->N_CELL_ID;
    }

    for (u16_m = 0; u16_m < SimParam->DMRS_NumInOneSlot; u16_m++) // symbol by symbol
    {
        // uIdx and vIdx Gen, TBD
        if (0 == SimParam->HopMod)// 0 - no seq hop no group hop
        {
            f_gh = 0;
            SimParam->PUSCH_DMRS_vIdx[u16_m] = 0;
        }
        else if (1 == SimParam->HopMod)// 1 - no seq hop
        {
			uwCInit = N_ID_RS / 30;

            RsGen_DMRS_PN_Hop_f(uwCInit,    // init
                                P_Seq_Op
                                );

            temp = 0;
            for (m = 0; m < 8; m++)
            {
                temp = temp + (int)(P_Seq_Op[8 * (SimParam->PUSCH_SymNum * SimParam->SlotIdx + SimParam->DMRS_SymIdx[u16_m]) + m] * pow(2.0, m)); //38.211
            }
            f_gh = temp % 30;
            SimParam->PUSCH_DMRS_vIdx[u16_m] = 0;
        }
        else // 2 - no group hop
        {
            RsGen_DMRS_PN_Hop_f(N_ID_RS,    // init
                                P_Seq_Op
                                );

            f_gh = 0;

            if (SimParam->PUSCH_RB_Num >= 12) // Mzc=PUSCH_RB_Num*SC_PER_RB/2 >= 6*SC_PER_RB
            {
                SimParam->PUSCH_DMRS_vIdx[u16_m] = P_Seq_Op[SimParam->PUSCH_SymNum * SimParam->SlotIdx + SimParam->DMRS_SymIdx[u16_m]];
            }
            else // otherwise
            {
                SimParam->PUSCH_DMRS_vIdx[u16_m] = 0;
            }
        }

        SimParam->PUSCH_DMRS_uIdx[u16_m] = (f_gh + N_ID_RS) % 30; // 38.211
    }

    SimParam->RS_SC_Num = (int)(SimParam->PUSCH_RB_Num * 12 / pow(2.0, 1));
    if (SimParam->RS_SC_Num > 30) // Sequence length >= 30
    {
        SimParam->Nzc = PrimTable_dmrs_Delta1[SimParam->PUSCH_RB_Num - 1];
        SimParam->cordic_fac = (int32)(PI_FLTP / (2 * SimParam->Nzc) * pow(2.0, 27 - 3));
        for (u16_m = 0; u16_m < SimParam->DMRS_NumInOneSlot; u16_m++)
        {
            uIdx = SimParam->PUSCH_DMRS_uIdx[u16_m];
            vIdx = SimParam->PUSCH_DMRS_vIdx[u16_m];
            RootSeqParamTemp = (float)(SimParam->Nzc * (uIdx + 1) / 31.0);
            SimParam->PUSCH_DMRS_q[u16_m] = (int)((int)(RootSeqParamTemp + 0.5) + vIdx * pow(-1.0, (int)(2 * RootSeqParamTemp)));
        }
    }

}

void RB_BitMapCalc(stULParamTable *SimParam)
{
    UINT16 u16_RBG_bit_Num = 0;
    int m;
    int32 DMRSReNum_PerSymb = 0;
    UINT8 RA_Type0_LastRBNum = 0;

    uint8 u8_DMRS_Table_start = 0;
    int   ColNumInterleave = 0; // SimParam->SCS_RbNum[SimParam->UeScsIdx]/(RowNumInterleave*SimParam->PUSCH_BundingSize)
    uint8 RowNumInterleave = 2;   // for PUSCH Interleave
    int   BWP_BundingNum = 0; // SimParam->SCS_RbNum[SimParam->UeScsIdx]/SimParam->PUSCH_BundingSize
    int   f_j = 0; // c, r, f(j) in 3GPP 38.211
    int RB_idx = 0; // used in Discontiguous

    for (m = 0; m < MAXRBNUM; m++)
    {
        SimParam->RB_BitMap[m] = 0;
        SimParam->PUSCH_RB_Idx[m] = 0;
    }
    // protection
    SimParam->RA_Type = RA_Contiguous;

    /* RB bit mapping */
    for (m = SimParam->PUSCH_VRB_START; m < SimParam->PUSCH_VRB_START + SimParam->PUSCH_RB_Num; m++) //useful RB
    {
        SimParam->RB_BitMap[m] = 1;
        SimParam->PUSCH_RB_Idx[m - SimParam->PUSCH_VRB_START] = m;
        SimParam->PUSCH_iRB2RBIdx[m] = m - SimParam->PUSCH_VRB_START; //
    } 
}
///=================================================================================================
/// pusch_re_pattern_HARQ.
///
/// @author guozhiyuan
/// @date   2018/4/03
///
/// @param [inout]     SimParam     参数输入结构体.
/// @par History
/// -
///       Date|       Author|        Version|        DESCRIPTION
/// ----------|-------------|---------------|-------------------
/// 2018-04-03|   Guozhiyuan|          0.0.1|            created
/// 2018-04-17|      Yangyan|          0.0.2|            封装和整理，添加DMRS和PUSCH共符号
///=================================================================================================
void pusch_re_pattern_HARQ(
    INOUT stULParamTable *SimParam,
    IN int16 SC_NUM_PER_SYM[MAXSYMNUM],
    IN int16 SC_NUM_PER_SYM_RESERVE[MAXSYMNUM],
    INOUT int16 *pusch_re_idx[MAXSYMNUM],
    INOUT int8 *pusch_reserve_flag[MAXSYMNUM],
    INOUT int8 *pusch_ack_punc_flag[MAXSYMNUM],
    IN    int  NLxQm

)
{
    int l, d, j, k, counter_re, counter_re_reserve, counter_ack, counter_ack_reserve, hopidx;

    //ini
    for (l = 0; l < MAXSYMNUM; l++)
    {
        // 38.212 6.2.7 step1 RESERVED ACK
        SimParam->ack_rsvd_d[l] = 0;
        SimParam->ack_rsvd_cnt[l] = 0; // m_RE_cnt
        SimParam->ack_d[l]  = 0;
    }

    for (hopidx = 0; hopidx < SimParam->N_Hop_PUSCH; hopidx++)
    {
        if (1 == SimParam->PUSCH_HARQ_Flag)
        {
            //step1  Harq info bits <=2 reserve
            //there is something wrong temporary
            if (SimParam->PUSCH_HARQ_A_Len <= 2)
            {
                //l = l_sch;
                l = SimParam->PUSCH_l_sch_HopEn[hopidx];
                counter_ack = 0 ;
                counter_ack_reserve = 0;

                while (counter_ack_reserve < SimParam->PUSCH_HARQ_E_Len_RESERVE_HopEn[hopidx])
                {
                    if (SC_NUM_PER_SYM[l] > 0)
                    {
                        if ((SimParam->PUSCH_HARQ_E_Len_RESERVE_HopEn[hopidx] - counter_ack_reserve) >= SC_NUM_PER_SYM[l] * NLxQm)
                        {
                            d = 1;
                            counter_re_reserve =  SC_NUM_PER_SYM[l] ;

                            if ((SimParam->PUSCH_HARQ_E_Len_HopEn[hopidx] - counter_ack) >= SC_NUM_PER_SYM[l] * NLxQm)
                            {
                                counter_re =  SC_NUM_PER_SYM[l] ;
                                SimParam->ack_d[l] = 1;
                            }
                            else
                            {
                                if ((SimParam->PUSCH_HARQ_E_Len_HopEn[hopidx] - counter_ack) % (NLxQm) == 0)
                                {
                                    counter_re = (int)((SimParam->PUSCH_HARQ_E_Len_HopEn[hopidx] - counter_ack) / (NLxQm));
                                }
                                else
                                {
                                    counter_re = (int)((SimParam->PUSCH_HARQ_E_Len_HopEn[hopidx] - counter_ack) / (NLxQm) + 1);
                                }

								SimParam->ack_d[l] = 1;
                            }

                            SimParam->ack_restart[l] = pusch_re_idx[l][0];
                            // 38.212 6.2.7 step1 RESERVED ACK
                            SimParam->ack_rsvd_d[l] = d;
                            SimParam->ack_rsvd_cnt[l] = counter_re_reserve; // m_RE_cnt

                        }
                        else //if ((SimParam->PUSCH_HARQ_E_Len_RESERVE - counter_ack_reserve) < SC_NUM_PER_SYM[l] * NL * Qm)
                        {
							d = 1;

                            if ((SimParam->PUSCH_HARQ_E_Len_RESERVE_HopEn[hopidx] - counter_ack_reserve) % (NLxQm) == 0)
                            {
                                counter_re_reserve = (int)((SimParam->PUSCH_HARQ_E_Len_RESERVE_HopEn[hopidx] - counter_ack_reserve) / (NLxQm));
                            }
                            else
                            {
                                counter_re_reserve = (int)((SimParam->PUSCH_HARQ_E_Len_RESERVE_HopEn[hopidx] - counter_ack_reserve) / (NLxQm) + 1);
                            }

                            if ((SimParam->PUSCH_HARQ_E_Len_HopEn[hopidx] - counter_ack) % (NLxQm) == 0)
                            {
                                counter_re = (int)((SimParam->PUSCH_HARQ_E_Len_HopEn[hopidx] - counter_ack) / (NLxQm));
                            }
                            else
                            {
                                counter_re = (int)((SimParam->PUSCH_HARQ_E_Len_HopEn[hopidx] - counter_ack) / (NLxQm) + 1);
                            }


							SimParam->ack_d[l] = 1;
                            SimParam->ack_restart[l] = pusch_re_idx[l][0];
                            // 38.212 6.2.7 step1 RESERVED ACK
                            SimParam->ack_rsvd_d[l] = d;
                            SimParam->ack_rsvd_cnt[l] = counter_re_reserve; // m_RE_cnt
                        }

                        counter_ack_reserve += counter_re_reserve * NLxQm; // update RESERVED ACK bit number
                        counter_ack += counter_re * NLxQm;                // update ACK bit number

                        SC_NUM_PER_SYM_RESERVE[l] += counter_re_reserve;

                        for (j = 0 ; j < counter_re_reserve ; j++)
                        {
                            pusch_reserve_flag[l][j * d] = 1;   // update RESERVED  Flag
                        }

                        for (j = 0 ; j < counter_re ; j++)
                        {
                            pusch_ack_punc_flag[l][j * d * SimParam->ack_d[l]] = 1; // update punctured ack Flag
                        }
                    }// end of  if (SC_NUM_PER_SYM[l] > 0)
                    l = l + 1;
                }// end of  while(counter_ack < SimParam->PUSCH_HARQ_E_Len)
            }  // end of  if(SimParam->PUSCH_HARQ_K_Len <= 2)
            //step2  Harq infobits >2 placing
            else //if(SimParam->PUSCH_HARQ_K_Len > 2)
            {
                l = SimParam->PUSCH_l_sch_HopEn[hopidx];
                counter_ack = 0 ;
                while (counter_ack < SimParam->PUSCH_HARQ_E_Len_HopEn[hopidx])
                {
                    if (SC_NUM_PER_SYM[l] > 0)
                    {
                        if ((SimParam->PUSCH_HARQ_E_Len_HopEn[hopidx] - counter_ack) >= SC_NUM_PER_SYM[l] * NLxQm)
                        {
                            d = 1;
                            counter_re =  SC_NUM_PER_SYM[l] ;

                            SimParam->ack_d[l] = d;
                            SimParam->ack_restart[l] = pusch_re_idx[l][0];
                        }
                        else //if ((SimParam->PUSCH_HARQ_E_Len_HopEn[hopidx] - counter_ack) < SC_NUM_PER_SYM[l] * Nl * Qm)
                        {
                            //d = floor(SC_NUM_PER_SYM[l] * Nl * Qm/(SimParam->PUSCH_HARQ_E_Len - counter_ack ));
                            //counter_re = ceil((SimParam->PUSCH_HARQ_E_Len - counter_ack )/Nl*Qm);
                            d = (int)(SC_NUM_PER_SYM[l] * NLxQm / (SimParam->PUSCH_HARQ_E_Len_HopEn[hopidx] - counter_ack));
                            counter_re = (int)((SimParam->PUSCH_HARQ_E_Len_HopEn[hopidx] - counter_ack + NLxQm - 1) / (NLxQm));
                            SimParam->ack_d[l] = d;
                            SimParam->ack_restart[l] = pusch_re_idx[l][0];
                        }
                        SC_NUM_PER_SYM[l] -= counter_re;

                        for (j = 0 ; j < counter_re ; j++)
                        {
                            k = pusch_re_idx[l][j * d]  ; // here is no problem , but not good
                            pusch_re_idx[l][j * d] = -1;
                            SimParam->pusch_re_flag[l][k] = 1;// -2: CSI2 punctring by ACK, -1: Data punctring by ACK, 0: UL-SCH, 1: ACK, 2:CSI1, 3: CSI2, 4: DMRS, 5: NULL, 6: SRS, 7:PT-RS
                            counter_ack = counter_ack +  NLxQm;
                        }
                    } // end of if (SC_NUM_PER_SYM[l] > 0)
                    l = l + 1;
                }       // end of while(counter_ack_reserve < SimParam->PUSCH_HARQ_E_Len_RESERVE_HopEn[hopidx])
            }   // end of if(SimParam->PUSCH_HARQ_A_Len <= 2)
        } // end of if(1 == SimParam->PUSCH_HARQ_Flag)
    } // end of for(hopidx=0; hopidx<SimParam->N_Hop_PUSCH; hopidx++)

    return;

}
///=================================================================================================
/// pusch_re_pattern_CSI.
///
/// @author guozhiyuan
/// @date   2018/4/03
///
/// @param [inout]     SimParam     参数输入结构体.
/// @par History
/// -
///       Date|       Author|        Version|        DESCRIPTION
/// ----------|-------------|---------------|-------------------
/// 2018-04-03|   Guozhiyuan|          0.0.1|            created
/// 2018-04-17|      Yangyan|          0.0.2|            封装和整理，添加DMRS和PUSCH共符号
///=================================================================================================
void pusch_re_pattern_CSI(
    INOUT stULParamTable *SimParam,
    IN int16 SC_NUM_PER_SYM[MAXSYMNUM],
    IN int16 SC_NUM_PER_SYM_RESERVE[MAXSYMNUM],
    IN int16 *pusch_re_idx[MAXSYMNUM],
    IN int16 *pusch_re_idx_swap[MAXSYMNUM],
    IN int    NLxQm,
    INOUT int8 *pusch_reserve_flag[MAXSYMNUM]
)
{
    int l, d, j, k, counter_re, l_csi, counter_csi1, hopidx;
    int iSym, iRe, MaxScNum;

    MaxScNum = SimParam->PUSCH_RB_Num * SC_PER_RB;
    for (l = 0; l < MAXSYMNUM; l++)
    {
        SimParam->csi1_d[l] = 0;
    }
    for (hopidx = 0; hopidx < SimParam->N_Hop_PUSCH; hopidx++)
    {
        //determine l_sch and l_uci
        l_csi = SimParam->PUSCH_l_csi_HopEn[hopidx]; // get first pusch symbol postion for CSI

        if (1 ==  SimParam->PUSCH_CSI1_Flag)
        {
            l = l_csi;
            counter_csi1 = 0 ;
            while ((SC_NUM_PER_SYM[l] - SC_NUM_PER_SYM_RESERVE[l]) <= 0)
            {
                l = l + 1;
            }

            while (counter_csi1 < SimParam->PUSCH_CSI1_E_Len_HopEn[hopidx])
            {
                if ((SC_NUM_PER_SYM[l] - SC_NUM_PER_SYM_RESERVE[l]) > 0)
                {
                    if ((SimParam->PUSCH_CSI1_E_Len_HopEn[hopidx] - counter_csi1) >= (SC_NUM_PER_SYM[l] - SC_NUM_PER_SYM_RESERVE[l]) * NLxQm)
                    {
                        d = 1;
                        counter_re =  SC_NUM_PER_SYM[l] - SC_NUM_PER_SYM_RESERVE[l] ;

                        SimParam->csi1_d[l] = d;
                        SimParam->csi1_restart[l] = pusch_re_idx[l][0];
                    }
                    else //if ((SimParam->PUSCH_CSI1_E_Len - counter_re) < (SC_NUM_PER_SYM[l]-SC_NUM_PER_SYM_RESERVE[l]) * NL * Qm)
                    {

						d = 1;
                        counter_re = (int)((SimParam->PUSCH_CSI1_E_Len_HopEn[hopidx] - counter_csi1 + NLxQm - 1) / (NLxQm));
                        SimParam->csi1_d[l] = d;
                        SimParam->csi1_restart[l] = pusch_re_idx[l][0];
                    }

                    SC_NUM_PER_SYM[l] -= counter_re;

                    if (SC_NUM_PER_SYM_RESERVE[l] > 0)
                    {
                        for (iRe = 0 ; iRe < MaxScNum; iRe++)
                        {
                            if (1 == pusch_reserve_flag[l][iRe])
                            {
                                pusch_re_idx[l][iRe] = -1;
                            }
                        }
                        memcpy(&pusch_re_idx_swap[l][0], &pusch_re_idx[l][0], MaxScNum * sizeof(int16));

                        k = 0;
                        for (iRe = 0 ; iRe < MaxScNum; iRe++)
                        {
                            if (pusch_re_idx_swap[l][iRe] >= 0)
                            {
                                pusch_re_idx[l][k] = pusch_re_idx_swap[l][iRe];
                                k++;
                            }
                        }
                    }


                    for (j = 0 ; j < counter_re ; j++)
                    {
                        k = pusch_re_idx[l][j * d]  ; // here is no problem , but not good
                        pusch_re_idx[l][j * d] = -1;
                        SimParam->pusch_re_flag[l][k] = 2;// -2: CSI2 punctring by ACK, -1: Data punctring by ACK, 0: UL-SCH, 1: ACK, 2:CSI1, 3: CSI2, 4: DMRS, 5: NULL, 6: SRS, 7:PT-RS
                        counter_csi1 = counter_csi1 + NLxQm;
                    }

                    if (SC_NUM_PER_SYM_RESERVE[l] > 0)
                    {
                        k = 0;
                        for (iRe = 0 ; iRe < MaxScNum; iRe++)
                        {
                            if (2 != SimParam->pusch_re_flag[l][iRe])
                            {
                                pusch_re_idx[l][k] = iRe;
                                k++;
                            }
                        }
                    }
                }// end of  if ((SC_NUM_PER_SYM[l] - SC_NUM_PER_SYM_RESERVE[l]) > 0)
                l = l + 1;
            }   //    end of while(counter_csi1 < SimParam->PUSCH_CSI1_E_Len)

            //update  pusch_re_idx    start
            for (iSym = 0 ; iSym < MAXSYMNUM; iSym++)
            {
                memcpy(&pusch_re_idx_swap[iSym][0], &pusch_re_idx[iSym][0], MaxScNum * sizeof(int16));
            }

            for (iSym = 0 ; iSym < MAXSYMNUM; iSym++)
            {
                k = 0;
                for (iRe = 0 ; iRe < MaxScNum; iRe++)
                {
                    if (pusch_re_idx_swap[iSym][iRe] >= 0)
                    {
                        pusch_re_idx[iSym][k] = pusch_re_idx_swap[iSym][iRe];
                        k++;
                    }
                }
            }
            //update  pusch_re_idx    end

        }// end of if(1 ==  SimParam->PUSCH_CSI_Flag)
    } // end of for(hopidx=0; hopidx<SimParam->N_Hop_PUSCH; hopidx++)
    return;

}
///=================================================================================================
/// pusch_re_pattern_CSI.
///
/// @author guozhiyuan
/// @date   2018/4/03
///
/// @param [inout]     SimParam     参数输入结构体.
/// @par History
/// -
///       Date|       Author|        Version|        DESCRIPTION
/// ----------|-------------|---------------|-------------------
/// 2018-04-03|   Guozhiyuan|          0.0.1|            created
/// 2018-04-17|      Yangyan|          0.0.2|            封装和整理，添加DMRS和PUSCH共符号
///=================================================================================================
void pusch_re_pattern_SCH(
    INOUT stULParamTable *SimParam
)
{
    int iSym, iRe, iRs, iLayer, uck2, fDMRS_delta, DMRSReNum_CDM;
    /* DMRS front located symbol mapping */
    DMRSReNum_CDM = 6 * SimParam->PUSCH_RB_Num; // DMRS mapping re number for each CDM group

    //g_re_flag
    for (iSym = 0 ; iSym < MAXSYMNUM; iSym++)
    {
        // Step 1 填充为pusch data
        if (0 == SimParam->u8_DMRS_Pos[iSym])
        {
            for (iRe = 0 ; iRe < SimParam->PUSCH_RB_Num * SC_PER_RB; iRe++)
            {
                SimParam->pusch_re_flag[iSym][iRe] = 0; // -2: CSI2 punctring by ACK, -1: Data punctring by ACK, 0: UL-SCH, 1: ACK, 2:CSI1, 3: CSI2, 4: DMRS, 5: NULL, 6: SRS, 7:PT-RS
            }

        }
        // Step 2 如果允许dmrs和pusch共符号,就将数据位置的iUE的数据和dmrs初始flag初始化为0,其他UE的dmrs位置初始化为5
        if ((1 == SimParam->u8_DMRS_Pos[iSym]) && (0 == SimParam->DMRS_SCH_Combin)) // dmrs ofdm symbol = [dmrs re for iUe, dmrs re for other UE] or [dmrs re for iUe]
        {
            for (iRe = 0 ; iRe < SimParam->PUSCH_RB_Num * SC_PER_RB; iRe++)
            {
                SimParam->pusch_re_flag[iSym][iRe] = 5; // -2: CSI2 punctring by ACK, -1: Data punctring by ACK, 0: UL-SCH, 1: ACK, 2:CSI1, 3: CSI2, 4: DMRS, 5: NULL, 6: SRS, 7:PT-RS
            }
        }
        // Step3 标记导频位置
        if (1 == SimParam->u8_DMRS_Pos[iSym])
        {
            for (iLayer = 0; iLayer < SimParam->Fixed_RI; iLayer++)
            {
                for (iRs = 0; iRs < DMRSReNum_CDM / 2; iRs++)
                {
                    for (uck2 = 0; uck2 < 2; uck2++)
                    {
                        // get fDMRS_delta
                        fDMRS_delta = (int)g_DMRS_delta[SimParam->PUSCH_DMRS_PortIdx[iLayer]][0];
                        iRe = fDMRS_delta + 4 * iRs + 2 * uck2; // PRB SC index

                        SimParam->pusch_re_flag[iSym][iRe] = 4; // -2: CSI2 punctring by ACK, -1: Data punctring by ACK, 0: UL-SCH, 1: ACK, 2:CSI1, 3: CSI2, 4: DMRS, 5: NULL, 6: SRS, 7:PT-RS
                        SimParam->pusch_re_flag_dmrsport[iSym][iLayer][iRe] = SimParam->PUSCH_DMRS_PortIdx[iLayer];//0~11->dmrs port0~dmrs port11,else->-1
                    }/* end for uck2 */
                }/* end for iRs */
            }
        }

		// Step4 标记PTRS位置
		if (1 == SimParam->UL_PTRS_present)
		{
			if (1 == SimParam->l_PTRS_Symb_flag[iSym]) // PTRS Symbol
			{
				for (iRe = 0; iRe < SimParam->PTRS_RE_Num; iRe++)
				{
					// PTRS port0
					SimParam->pusch_re_flag[iSym][SimParam->k_PTRS_RE_pos[0][iRe]] = 7; // -2: CSI2 punctring by ACK, -1: Data punctring by ACK, 0: UL-SCH, 1: ACK, 2:CSI1, 3: CSI2, 4: DMRS, 5: NULL, 6: SRS, 7:PT-RS
				}
			}
		}
    }

    return;

}

///=================================================================================================
/// pusch_re_pattern.
///
/// @author guozhiyuan
/// @date   2018/4/03
///
/// @param [inout]     SimParam     参数输入结构体.
/// @par History
/// -
///       Date|       Author|        Version|        DESCRIPTION
/// ----------|-------------|---------------|-------------------
/// 2018-04-03|   Guozhiyuan|          0.0.1|            created
/// 2018-04-17|      Yangyan|          0.0.2|            封装和整理，添加DMRS和PUSCH共符号
///=================================================================================================
void pusch_re_pattern(stULParamTable *SimParam)
{
    //38.212 6.2.7
    int iSym, iRe, MaxScNum, NL, Qm, NLxQm, k;

    //int16 fDMRS_delta = 0;
    int16 SC_NUM_PER_SYM[MAXSYMNUM] = {0}; //calc sc number per symbol
    int16 SC_NUM_PER_SYM_RESERVE[MAXSYMNUM] = {0}; //calc sc number per symbol

    //re and re flag
    int8  *pusch_reserve_flag[MAXSYMNUM];
    int8  *pusch_ack_punc_flag[MAXSYMNUM];
    int16 *pusch_re_idx[MAXSYMNUM];
    int16 *pusch_re_idx_swap[MAXSYMNUM];

    MaxScNum = SimParam->PUSCH_RB_Num * SC_PER_RB;
    //calc sc number per symbol
	for (iSym = 0; iSym < MAXSYMNUM; iSym++)
	{
		if (0 == SimParam->u8_DMRS_Pos[iSym]) //pusch ofdm symbol
		{		
			if (1 == SimParam->l_PTRS_Symb_flag[iSym])
			{
				SC_NUM_PER_SYM[iSym] = MaxScNum - SimParam->PTRS_RE_Num; // ptrs发送re需要预留
			}
			else
			{
				SC_NUM_PER_SYM[iSym] = MaxScNum;
			}
		}
        else if (1 == SimParam->u8_DMRS_Pos[iSym]) //dmrs ofdm symbol 不放置UCI，38.212-6.2.7
        {
            SC_NUM_PER_SYM[iSym] = 0;
        }
        else
        {
            SC_NUM_PER_SYM[iSym] = 0;
        }
    }
    //

	Qm = SimParam->ModuMod[0] > 0 ? (SimParam->ModuMod[0] * 2) : 1;
   
    NL = SimParam->LayerNumOf1cw[0];
    NLxQm = NL * Qm;
    memset(&SimParam->pusch_re_flag[0][0], 5, MAXSYMNUM * MAXRBNUM * SC_PER_RB * sizeof(int8)); // -2: CSI2 punctring by ACK, -1: Data punctring by ACK, 0: UL-SCH, 1: ACK, 2:CSI1, 3: CSI2, 4: DMRS, 5: NULL, 6: SRS, 7:PT-RS, 8:ACK覆盖CSI2 9:ACK覆盖 SCH
    //memset(&SimParam->pusch_re_flag_dmrsport[0][0],-1,MAXSYMNUM*MAXRBNUM*SC_PER_RB*sizeof(int8));//0~11->dmrs port0 ~ dmrs port11,else ->-1
    memset(&SimParam->pusch_re_flag_dmrsport[0][0][0], -1, 12 * MAXSYMNUM * MAXRBNUM * SC_PER_RB * sizeof(int8)); //0~11->dmrs port0 ~ dmrs port11,else ->-1
    for (iSym = 0 ; iSym < MAXSYMNUM; iSym++)
    {
        pusch_reserve_flag[iSym] = (int8 *)malloc(MaxScNum * sizeof(int8));
        pusch_ack_punc_flag[iSym] = (int8 *)malloc(MaxScNum * sizeof(int8));
        pusch_re_idx[iSym] = (int16 *)malloc(MaxScNum * sizeof(int16));
        pusch_re_idx_swap[iSym] = (int16 *)malloc(MaxScNum * sizeof(int16));
    }
    // SCH, DMRS and PTRS pattern
    pusch_re_pattern_SCH(SimParam);
    // ini
    for (iSym = 0 ; iSym < MAXSYMNUM; iSym++)
    {
        for (iRe = 0 ; iRe < MaxScNum; iRe++)
        {
            pusch_reserve_flag[iSym][iRe] = -1 ;// determin if a re is reserved
            pusch_ack_punc_flag[iSym][iRe] = -1 ;// determin if a re is punctured
            pusch_re_idx[iSym][iRe] = iRe;      // frequency domain carrier index
        }
    }

	// delete PTRS pos
	for (iSym = 0; iSym < MAXSYMNUM; iSym++)
	{
		for (iRe = 0; iRe < MaxScNum; iRe++)
		{
			if (7 == SimParam->pusch_re_flag[iSym][iRe])
			{
				pusch_re_idx[iSym][iRe] = -1;// determin if a re is reserved
			}
		}
	}

	//update g_re_idx, deleted PTRS Pos for HARQ
	for (iSym = 0; iSym < MAXSYMNUM; iSym++)
	{
		memcpy(&pusch_re_idx_swap[iSym][0], &pusch_re_idx[iSym][0], MaxScNum * sizeof(int16));
	}

	for (iSym = 0; iSym < MAXSYMNUM; iSym++)
	{
		k = 0;
		for (iRe = 0; iRe < MaxScNum; iRe++)
		{
			if (pusch_re_idx_swap[iSym][iRe] >= 0)
			{
				pusch_re_idx[iSym][k] = pusch_re_idx_swap[iSym][iRe];
				k++;
			}
		}
	}

	// CSI pattern
	pusch_re_pattern_CSI(SimParam, SC_NUM_PER_SYM, SC_NUM_PER_SYM_RESERVE, pusch_re_idx, pusch_re_idx_swap, NLxQm, pusch_reserve_flag);

    //update g_re_idx, deleted HARQ Pos for CSI1 and CSI2
    for (iSym = 0 ; iSym < MAXSYMNUM; iSym++)
    {
        memcpy(&pusch_re_idx_swap[iSym][0], &pusch_re_idx[iSym][0], MaxScNum * sizeof(int16));
    }

    for (iSym = 0 ; iSym < MAXSYMNUM; iSym++)
    {
        k = 0;
        for (iRe = 0 ; iRe < MaxScNum; iRe++)
        {
            if (pusch_re_idx_swap[iSym][iRe] >= 0)
            {
                pusch_re_idx[iSym][k] = pusch_re_idx_swap[iSym][iRe];
                k++;
            }
        }
    }


	// HARQ pattern
	pusch_re_pattern_HARQ(SimParam, SC_NUM_PER_SYM, SC_NUM_PER_SYM_RESERVE, pusch_re_idx, pusch_reserve_flag, pusch_ack_punc_flag, NLxQm);

    // ACK reserved pattern
    for (iSym = 0 ; iSym < MAXSYMNUM; iSym++)
    {
        for (iRe = 0 ; iRe < MaxScNum; iRe++)
        {
            if (1 == pusch_ack_punc_flag[iSym][iRe])
            {
                if (0 == SimParam->pusch_re_flag[iSym][iRe])
                {
                    SimParam->pusch_re_flag[iSym][iRe] = -1; // -2:ACK-CSI2_PUNC , -1: ACK-ULSCH_PUNC 0: UL-SCH, 1: ACK, 2:CSI1, 3: CSI2, 4: DMRS, 5: NULL, 6: SRS, 7:PT-RS
                }
                else if (3 == SimParam->pusch_re_flag[iSym][iRe])
                {
                    SimParam->pusch_re_flag[iSym][iRe] = -2; // -2:ACK-CSI2_PUNC , -1: ACK-ULSCH_PUNC 0: UL-SCH, 1: ACK, 2:CSI1, 3: CSI2, 4: DMRS, 5: NULL, 6: SRS, 7:PT-RS
                }
            }
        }
    }

    // sch bit length calc
    SimParam->PUSCHData_BitLen[0] = 0 ;
    SimParam->PUSCHData_BitLen[1] = 0 ;

    for (iSym = 0 ; iSym < MAXSYMNUM; iSym++)
    {
		SimParam->pusch_re_cnt[iSym] = 0;
        for (iRe = 0 ; iRe < MaxScNum; iRe++)
        {
            if ((-1 == SimParam->pusch_re_flag[iSym][iRe]) || (0 == SimParam->pusch_re_flag[iSym][iRe]))
            {
                SimParam->PUSCHData_BitLen[0] += NLxQm;
                SimParam->PUSCHData_BitLen[1] += NLxQm;
				SimParam->pusch_re_cnt[iSym] += 1; // 每个符号上用于映射pus的RE数
            }
        }
    }

    //Memory free
    for (iSym = 0 ; iSym < MAXSYMNUM; iSym++)
    {
        free(pusch_reserve_flag[iSym]);
        free(pusch_re_idx[iSym]);
        free(pusch_re_idx_swap[iSym]);
    }
    return;

}



///=================================================================================================
/// PuschCrcLenCalc.
///
/// @author guozhiyuan
/// @date   2018/5/08
///
/// @param [inout]     SimParam     参数输入结构体.
/// @par History
/// -
///       Date|       Author|        Version|        DESCRIPTION
/// ----------|-------------|---------------|-------------------
/// 2018-05-03|   Guozhiyuan|          0.0.1|            created
///=================================================================================================

uint8 PuschCrcLenCalc(int16 PayloadLen)
{
    if (PayloadLen < 12)
    {
        return 0;
    }
    else if (PayloadLen <= 19)  //12<= A <=19
    {
        return 6;
    }
    else
    {
        return 11;
    }
}

///=================================================================================================
/// vGet_C_Kr
///
/// @author shanshan
/// @date   2018/6/15
///
/// @param [in]    uwLen            TBS参数输入
/// @param [in]    CodeBlkNum       码块个数
/// @param [in]    TBLenAddAllCrc   TBS添加CRC后的长度
/// @par History
/// -
///       Date|       Author|        Version|        DESCRIPTION
/// ----------|-------------|---------------|-------------------
/// 2018-06-15|   Shanshan|          0.0.1|            created
///=================================================================================================
UINT32 vGet_Kr_cal(IN UINT32 uwLen, IN UINT32 CodeBlkNum, IN UINT32 TBLenAddAllCrc, IN float fRate)
{
    int BGType = 0;
    UINT32 uwCodeLenAft, uwInfoK, uwKb, uwZTmp ;
    UINT8  i, j, ucIdxRow, ucIdxCol;
    INT32  wTmp, wTmp1;
    int  InfoLen, Kr;

    //-------------- choose BG Type ------------------------------//
    if ((uwLen <= 292) || (uwLen <= 3824 && fRate <= 0.67) || fRate <= 0.25) //38.212 v1.1.1
    {
        BGType = LDPC_BG2;
        InfoLen = 10;
    }
    else
    {
        BGType = LDPC_BG1;
        InfoLen = 22;
    }

    //calculate code block num
    /*if (LDPC_BG1 == BGType)//BG1
    {
        if (TBLenAddAllCrc <= MAX_CBLEN_BG1)
        {
            CBCrcLen = 0;
            uwCodeLenAft = TBLenAddAllCrc;
        }
        else
        {
            CBCrcLen = 24;
            uwCodeLenAft = TBLenAddAllCrc + (CodeBlkNum) * CBCrcLen;
        }
    }
    else
    {
        if (TBLenAddAllCrc <= MAX_CBLEN_BG2)//BG2
        {
            CBCrcLen = 0;
            uwCodeLenAft = TBLenAddAllCrc;
        }
        else
        {
            CBCrcLen = 24;
            uwCodeLenAft = TBLenAddAllCrc + CodeBlkNum * CBCrcLen;
        }
    }*/
    uwCodeLenAft = TBLenAddAllCrc; // 包含TBS+TBCRC和CBCRC*CodeBlkNum
    //calculate K'
    uwInfoK = (UINT32)(uwCodeLenAft / CodeBlkNum);
    if (uwCodeLenAft % CodeBlkNum > 0)
    {
        printf("error: uwCodeLenAft / CodeBlkNum is not interger!\n");
    }
    if (CodeBlkNum > MAX_CB_NUM)
    {
        printf("error:  MAX_CB_NUM is smaller than uwCodeBlkNum!\n");
    }
    //calculate Kb used for calculating Z
    if (LDPC_BG1 == BGType)
    {
        uwKb = 22;
    }
    else
    {
        if (TBLenAddAllCrc > 640)
        {
            uwKb = 10;
        }
        else if (TBLenAddAllCrc > 560)
        {
            uwKb = 9;
        }
        else if (TBLenAddAllCrc > 192)
        {
            uwKb = 8;
        }
        else
        {
            uwKb = 6;
        }
    }

    //calculate Z
    wTmp = 9999;
    uwZTmp = (UINT32)ceil((float)uwInfoK / uwKb);
    ucIdxRow = 0;
    ucIdxCol = 0;
    for (i = 0; i < 8; i++)
    {
        for (j = 0; j < 8; j++)
        {
            wTmp1 =  auwZ[i][j] - uwZTmp;
            if ((wTmp1 >= 0) && (wTmp1 < wTmp))
            {
                wTmp = wTmp1;
                ucIdxRow = i;
                ucIdxCol = j;
            }
        }
    }

    Kr = auwZ[ucIdxRow][ucIdxCol] * InfoLen; // K = Kb*Z
    return Kr;
}

///=================================================================================================
/// Pusch_RateMatch.
///
/// @author guozhiyuan
/// @date   2018/5/08
///
/// @param [inout]     SimParam     参数输入结构体.
/// @par History
/// -
///       Date|       Author|        Version|        DESCRIPTION
/// ----------|-------------|---------------|-------------------
/// 2018-05-03|   Guozhiyuan|          0.0.1|            created
///=================================================================================================
void Pusch_RateMatch(stULParamTable *SimParam)
{

    uint8 Lack = 0, Lcsi1 = 0, Lcsi2 = 0, T;
    int Qm, NL, NLxQm;

	Qm = SimParam->ModuMod[0] > 0 ? (SimParam->ModuMod[0] * 2) : 1;
    
    NL = SimParam->LayerNumOf1cw[0];
    NLxQm = NL * Qm;

    if (SimParam->PUSCHMultiFlag == 1)
    {
        //ACK RATE MATCH
        if (1 == SimParam->PUSCH_HARQ_Flag)
        {
            Lack = PuschCrcLenCalc(SimParam->PUSCH_HARQ_A_Len);

            if (1 == SimParam->PUSCH_SCH_Flag)   // UL-SCH exist
            {
                SimParam->PUSCH_HARQ_RENum = (int16)ceil((SimParam->PUSCH_HARQ_A_Len + Lack) * SimParam->PUSCH_HARQ_BetaOffset *  SimParam->PUSCH_UCI_RE_Num / SimParam->PUSCH_SCH_B_Len[0]);
                SimParam->PUSCH_HARQ_RENum = (int16)MIN(SimParam->PUSCH_HARQ_RENum, ceil(SimParam->PUSCH_Alpha * SimParam->PUSCH_UCI_RE_Num));
            }
            else  // UL-SCH not exist
            {
                SimParam->PUSCH_HARQ_RENum = (int16)ceil((SimParam->PUSCH_HARQ_A_Len + Lack) * SimParam->PUSCH_HARQ_BetaOffset / (SimParam->fRate[0] * Qm));
                SimParam->PUSCH_HARQ_RENum = (int16)MIN(SimParam->PUSCH_HARQ_RENum, ceil(SimParam->PUSCH_Alpha * SimParam->PUSCH_UCI_RE_Num));
            }

            if ((1 == SimParam->PUSCH_HARQ_A_Len) || (2 == SimParam->PUSCH_HARQ_A_Len))
            {
                // SimParam->PUSCH_HARQ_A_Len = 2
                // Lack = 0;

                if (1 == SimParam->PUSCH_SCH_Flag)   // UL-SCH exist
                {
                    SimParam->PUSCH_HARQ_RENum_RESERVE = (int16)ceil((2 + 0) * SimParam->PUSCH_HARQ_BetaOffset *  SimParam->PUSCH_UCI_RE_Num / SimParam->PUSCH_SCH_B_Len[0]);
                    SimParam->PUSCH_HARQ_RENum_RESERVE = (int16)MIN(SimParam->PUSCH_HARQ_RENum_RESERVE, ceil(SimParam->PUSCH_Alpha * SimParam->PUSCH_UCI_RE_Num));
                }
                else // UL-SCH not exist
                {
                    SimParam->PUSCH_HARQ_RENum_RESERVE = (int16)ceil((2 + 0) * SimParam->PUSCH_HARQ_BetaOffset / (SimParam->fRate[0] * Qm));
                    SimParam->PUSCH_HARQ_RENum_RESERVE = (int16)MIN(SimParam->PUSCH_HARQ_RENum_RESERVE, ceil(SimParam->PUSCH_Alpha * SimParam->PUSCH_UCI_RE_Num));
                }
            }
        }

        //CSI1 RATE MATCH
        if (1 == SimParam->PUSCH_CSI1_Flag) // UL-SCH exist
        {
            Lcsi1 = PuschCrcLenCalc(SimParam->PUSCH_CSI1_A_Len);
            if (1 == SimParam->PUSCH_SCH_Flag)   // UL-SCH exist
            {
                SimParam->PUSCH_CSI1_RENum = (int16)ceil((SimParam->PUSCH_CSI1_A_Len + Lcsi1) * SimParam->PUSCH_CSI1_BetaOffset *  SimParam->PUSCH_UCI_RE_Num / SimParam->PUSCH_SCH_B_Len[0]);
                SimParam->PUSCH_CSI1_RENum = (int16)MIN(SimParam->PUSCH_CSI1_RENum, ceil(SimParam->PUSCH_Alpha * SimParam->PUSCH_UCI_RE_Num) - SimParam->PUSCH_HARQ_RENum);

            }
            else  // UL-SCH not exist
            {
                SimParam->PUSCH_CSI1_RENum = SimParam->PUSCH_UCI_RE_Num - SimParam->PUSCH_HARQ_RENum;
            }
        }

        SimParam->PUSCH_HARQ_K_Len = SimParam->PUSCH_HARQ_A_Len + Lack;
        SimParam->PUSCH_CSI1_K_Len = SimParam->PUSCH_CSI1_A_Len + Lcsi1;
    }
    else
    {
        SimParam->PUSCH_HARQ_K_Len = 0;
        SimParam->PUSCH_CSI1_K_Len = 0;
        SimParam->PUSCH_HARQ_RENum = 0;
        SimParam->PUSCH_HARQ_RENum_RESERVE = 0;
        SimParam->PUSCH_CSI1_RENum = 0;

    }

    // bit length after RM
    SimParam->PUSCH_HARQ_E_Len_RESERVE = NLxQm * SimParam->PUSCH_HARQ_RENum_RESERVE;
    SimParam->PUSCH_HARQ_E_Len = NLxQm * SimParam->PUSCH_HARQ_RENum;
    SimParam->PUSCH_CSI1_E_Len = NLxQm * SimParam->PUSCH_CSI1_RENum;
    //
    SimParam->PUSCH_HARQ_POLAR_T = 0;
    SimParam->PUSCH_CSI1_POLAR_T = 0;
    if ((SimParam->PUSCH_HARQ_A_Len > 11) && (SimParam->PUSCH_HARQ_Flag > 0))
    {
        T = (UINT8)floor(sqrt((float)2 * SimParam->PUSCH_HARQ_E_Len));
        T += (T * (T + 1) / 2 < SimParam->PUSCH_HARQ_E_Len) ? 1 : 0;
        SimParam->PUSCH_HARQ_POLAR_T = T;
    }
    if ((SimParam->PUSCH_CSI1_A_Len > 11) && (SimParam->PUSCH_CSI1_Flag > 0))
    {
        T = (UINT8)floor(sqrt((float)2 * SimParam->PUSCH_CSI1_E_Len));
        T += (T * (T + 1) / 2 < SimParam->PUSCH_CSI1_E_Len) ? 1 : 0;
        SimParam->PUSCH_CSI1_POLAR_T = T;
    }

}
///=================================================================================================
/// Pusch_RateMatch_HopEn.
///
/// @author shanshan
/// @date   2018/10/08
///
/// @param [inout]     SimParam     参数输入结构体.
/// @par History
/// -
///       Date|       Author|        Version|        DESCRIPTION
/// ----------|-------------|---------------|-------------------
/// 2018-10-08|     shanshan|          0.0.1|            created
///=================================================================================================
void Pusch_RateMatch_HopEn(stULParamTable *SimParam)
{
    uint16 M1 = 0, M2 = 0, M3 = 0;
    int isymb, DMRS_SymbPos = 0;
    int Qm, NL, NLxQm;

	Qm = SimParam->ModuMod[0] > 0 ? (SimParam->ModuMod[0] * 2) : 1;
    NL = SimParam->LayerNumOf1cw[0];
    NLxQm = NL * Qm;

    if (0 == SimParam->frequencyHoppFlag) // no hop
    {
        SimParam->N_Hop_PUSCH = 1;

        // Symbol number in one slot
        SimParam->PUSCH_SymNum_HopEn[0] = SimParam->PUSCH_SymNum;

        // bit length after RM
        SimParam->PUSCH_HARQ_E_Len_HopEn[0] = SimParam->PUSCH_HARQ_E_Len;
        SimParam->PUSCH_HARQ_E_Len_RESERVE_HopEn[0] = SimParam->PUSCH_HARQ_E_Len_RESERVE;
        SimParam->PUSCH_CSI1_E_Len_HopEn[0] = SimParam->PUSCH_CSI1_E_Len;

        // symbol start
        SimParam->PUSCH_l_sch_HopEn[0] = (SimParam->DMRS_SymIdx[0] + SimParam->PUSCH_DMRS_SymNum - 1) + 1; // first ack symbol pos
        SimParam->PUSCH_l_csi_HopEn[0] = SimParam->PUSCH_Symb_Start; // first csi symbol pos

    }
    else if (1 == SimParam->frequencyHoppFlag) // intraslot hop is enable
    {
        SimParam->N_Hop_PUSCH = 2;

        // Symbol number in one hop
        SimParam->PUSCH_SymNum_HopEn[0] = SimParam->PUSCH_SymNum / 2; // symbol number of first hop
        SimParam->PUSCH_SymNum_HopEn[1] = SimParam->PUSCH_SymNum - SimParam->PUSCH_SymNum_HopEn[0];  // symbol number of second hop

        // ack reserved
        SimParam->PUSCH_HARQ_E_Len_RESERVE_HopEn[0] = NLxQm * (SimParam->PUSCH_HARQ_E_Len_RESERVE / (NLxQm * 2)); // sc number of first hop
        SimParam->PUSCH_HARQ_E_Len_RESERVE_HopEn[1] = SimParam->PUSCH_HARQ_E_Len_RESERVE - SimParam->PUSCH_HARQ_E_Len_RESERVE_HopEn[0];  // sc number of second hop

        // bit length after RM
        if (1 == SimParam->PUSCH_SCH_Flag) // with SCH
        {
            if (1 == SimParam->PUSCH_HARQ_Flag) // ack
            {
                SimParam->PUSCH_HARQ_E_Len_HopEn[0] = NLxQm * (SimParam->PUSCH_HARQ_E_Len / (NLxQm * 2));
                SimParam->PUSCH_HARQ_E_Len_HopEn[1] = SimParam->PUSCH_HARQ_E_Len - SimParam->PUSCH_HARQ_E_Len_HopEn[0];
            }

            if (1 == SimParam->PUSCH_CSI1_Flag) // csi1
            {
                SimParam->PUSCH_CSI1_E_Len_HopEn[0] = NLxQm * (SimParam->PUSCH_CSI1_E_Len / (NLxQm * 2));
                SimParam->PUSCH_CSI1_E_Len_HopEn[1] = SimParam->PUSCH_CSI1_E_Len - SimParam->PUSCH_CSI1_E_Len_HopEn[0];
            }
        }
        else // without SCH
        {
            // calc M1, M2 and M3
            for (isymb = SimParam->PUSCH_Symb_Start; isymb < SimParam->PUSCH_Symb_Start + SimParam->PUSCH_SymNum_HopEn[0]; isymb++)
            {
                if (SimParam->u8_DMRS_Pos[isymb] == 0) // non-DMRS
                {
                    M1 = M1 + SimParam->PUSCH_RB_Num * SC_PER_RB; // total Sc number of first hop

                    if (isymb > SimParam->DMRS_SymIdx[0])
                    {
                        M3 = M3 + SimParam->PUSCH_RB_Num * SC_PER_RB; // total ack Sc number of first hop
                    }
                }
            }
            for (isymb = SimParam->PUSCH_Symb_Start + SimParam->PUSCH_SymNum_HopEn[0]; isymb < SimParam->PUSCH_Symb_Start + SimParam->PUSCH_SymNum; isymb++)
            {
                if (SimParam->u8_DMRS_Pos[isymb] == 0) // non-DMRS
                {
                    M2 = M2 + SimParam->PUSCH_RB_Num * SC_PER_RB; // total Sc number of second hop
                }
            }

            // ack
            SimParam->PUSCH_HARQ_E_Len_HopEn[0] = min(NLxQm * (SimParam->PUSCH_HARQ_E_Len / (NLxQm * 2)), M3 * NLxQm);
            SimParam->PUSCH_HARQ_E_Len_HopEn[1] = SimParam->PUSCH_HARQ_E_Len - SimParam->PUSCH_HARQ_E_Len_HopEn[0];

            // csi1
            SimParam->PUSCH_CSI1_E_Len_HopEn[0] = M1 * NLxQm - SimParam->PUSCH_HARQ_E_Len_HopEn[0];
            SimParam->PUSCH_CSI1_E_Len_HopEn[1] = SimParam->PUSCH_CSI1_E_Len - SimParam->PUSCH_CSI1_E_Len_HopEn[0];

        } // end of if (1 == SimParam->PUSCH_SCH_Flag) // with SCH

        // symbol start
        SimParam->PUSCH_l_sch_HopEn[0] = (SimParam->DMRS_SymIdx[0] + SimParam->PUSCH_DMRS_SymNum - 1) + 1; // first ack symbol pos of first hop

        for (isymb = SimParam->PUSCH_Symb_Start + SimParam->PUSCH_SymNum_HopEn[0]; isymb < SimParam->PUSCH_Symb_Start + SimParam->PUSCH_SymNum; isymb++)
        {
            if (SimParam->u8_DMRS_Pos[isymb] == 1) // DMRS pos
            {
                DMRS_SymbPos = isymb;
                break; // find the first DMRS pos in the second hop
            }
        }
        SimParam->PUSCH_l_sch_HopEn[1] = (DMRS_SymbPos + SimParam->PUSCH_DMRS_SymNum - 1) + 1; // first ack symbol pos of second hop

        SimParam->PUSCH_l_csi_HopEn[0] = SimParam->PUSCH_Symb_Start; // first csi symbol pos of first hop
        if (1 == SimParam->u8_DMRS_Pos[SimParam->PUSCH_l_csi_HopEn[0]]) // first symbol is dmrs
        {
            SimParam->PUSCH_l_csi_HopEn[0] = SimParam->PUSCH_l_csi_HopEn[0] + SimParam->PUSCH_DMRS_SymNum; // first csi symbol pos of first hop
        }

        SimParam->PUSCH_l_csi_HopEn[1] = SimParam->PUSCH_Symb_Start + SimParam->PUSCH_SymNum_HopEn[0]; // first csi symbol pos of second hop
        if (1 == SimParam->u8_DMRS_Pos[SimParam->PUSCH_l_csi_HopEn[1]]) // first symbol is dmrs
        {
            SimParam->PUSCH_l_csi_HopEn[1] = SimParam->PUSCH_l_csi_HopEn[1] + SimParam->PUSCH_DMRS_SymNum; // first csi symbol pos of second hop
        }

    } // end of if (1 == SimParam->HopMod) // no hop
    else
    {
        ; //后续添加时隙间跳频分支。
    }
}
///=================================================================================================
/// HybridDFT_para_gen.
///
/// @author zhangyanqun
/// @date   2018/06/01
///
/// @param [inout]     SimParam     参数输入结构体.
/// @out stagenum\shift_factor\reverse_order\num_shift\radix_array
/// -
///       Date|       Author|        Version|        DESCRIPTION
/// ----------|-------------|---------------|-------------------
/// 2018-06-01|   zhangyanqun|          0.0.1|            created
///=================================================================================================
void HybridDFT_para_gen(stULParamTable *SimParam)
{
    int stage, num_shift;
    int radix_array[11] = {0};
	int radix_array_sub[10] = { 0 };
    int N_DFT, i;    //z is a flag indictor of modulation scheme
    char shift_factor[11] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
    int order_table[3240];
	int Npath = 2; // 2或者4
    memset(order_table, 0, 3240 * sizeof(int));
    
    N_DFT = SimParam->PUSCH_RB_Num * 12;
	DFT_Shift_Choose(N_DFT, shift_factor);

	stage = SimParam->P_Alpha2 + SimParam->P_Alpha3 + SimParam->P_Alpha5;
    for (i = 0; i < SimParam->P_Alpha2; i++)
    {
        radix_array[i] = 2;
    }
    for (i = 0; i < SimParam->P_Alpha3; i++)
    {
        radix_array[SimParam->P_Alpha2 + i] = 3;
    }
    for (i = 0; i < SimParam->P_Alpha5; i++)
    {
        radix_array[SimParam->P_Alpha2 + SimParam->P_Alpha3 + i] = 5;
    }

	for (i = 0; i < (int)(stage-log2(Npath)); i++)
	{
		radix_array_sub[i] = radix_array[i + (int)(log2(Npath))];
	}

	///generate shift factor end
	REVERSAL_ORDER_IDX_hy(N_DFT/Npath, radix_array_sub, order_table);
	///generate reverse order
	SimParam->stagenum = stage- (int)(log2(Npath));
	num_shift = 1; // 两路累加的移位因子
	for (i = 0; i < stage- (int)(log2(Npath)); i++)
	{
		SimParam->radix_array[i] = radix_array_sub[i];
		SimParam->shift_factor[i] = shift_factor[i + (int)(log2(Npath))];
		num_shift = num_shift + SimParam->shift_factor[i];
	}

	SimParam->num_shift = num_shift;   //get num_shift to calculate fix Beta_DMRS
	for (i = 0; i < N_DFT / Npath; i++)
	{
		SimParam->order_table[i] = order_table[i];
	}

    ///assign value start
}

///=================================================================================================
/// DFT_Shift_Choose.
///
/// @author shanshan
/// @date   2021/11/29
///
/// @param [inout]     n_point(FFT point) shift for fgpg_fft_ip_core
/// -
///       Date|       Author|        Version|        DESCRIPTION
/// ----------|-------------|---------------|-------------------
/// 2021-11-29|     shanshan|          0.0.1|            created
///=================================================================================================
void DFT_Shift_Choose(int DFT_Len, char shift_factor[11])
{
	int i,dft_idx;

	switch (DFT_Len) {
	case 12: dft_idx = 0; break;
	case 24: dft_idx = 1; break;
	case 36: dft_idx = 2; break;
	case 48: dft_idx = 3; break;
	case 60: dft_idx = 4; break;
	case 72: dft_idx = 5; break;
	case 96: dft_idx = 6; break;
	case 108: dft_idx = 7; break;
	case 120: dft_idx = 8; break;
	case 144: dft_idx = 9; break;
	case 180: dft_idx = 10; break;
	case 192: dft_idx = 11; break;
	case 216: dft_idx = 12; break;
	case 240: dft_idx = 13; break;
	case 288: dft_idx = 14; break;
	case 300: dft_idx = 15; break;
	case 324: dft_idx = 16; break;
	case 360: dft_idx = 17; break;
	case 384: dft_idx = 18; break;
	case 432: dft_idx = 19; break;
	case 480: dft_idx = 20; break;
	case 540: dft_idx = 21; break;
	case 576: dft_idx = 22; break;
	case 600: dft_idx = 23; break;
	case 648: dft_idx = 24; break;
	case 720: dft_idx = 25; break;
	case 768: dft_idx = 26; break;
	case 864: dft_idx = 27; break;
	case 900: dft_idx = 28; break;
	case 960: dft_idx = 29; break;
	case 972: dft_idx = 30; break;
	case 1080: dft_idx = 31; break;
	case 1152: dft_idx = 32; break;
	case 1200: dft_idx = 33; break;
	case 1296: dft_idx = 34; break;
	case 1440: dft_idx = 35; break;
	case 1500: dft_idx = 36; break;
	case 1536: dft_idx = 37; break;
	case 1620: dft_idx = 38; break;
	case 1728: dft_idx = 39; break;
	case 1800: dft_idx = 40; break;
	case 1920: dft_idx = 41; break;
	case 1944: dft_idx = 42; break;
	case 2160: dft_idx = 43; break;
	case 2304: dft_idx = 44; break;
	case 2400: dft_idx = 45; break;
	case 2592: dft_idx = 46; break;
	case 2700: dft_idx = 47; break;
	case 2880: dft_idx = 48; break;
	case 2916: dft_idx = 49; break;
	case 3000: dft_idx = 50; break;
	case 3072: dft_idx = 51; break;
	case 3240: dft_idx = 52; break;
	}

	// calc shift_factor
	for (i = 0; i < 11; i++)
	{
		shift_factor[i] = FPGA_RightShift[dft_idx][i];
	}
}

///=================================================================================================
/// REVERSAL_ORDER_IDX_hy.
///
/// @author zhangyanqun
/// @date   2018/06/01
///
/// @param [inout]     n_point(DFT point) radix_array(hybrid radix)
/// @out order (not exactly reverse order but reshape to fit fpga )
/// -
///       Date|       Author|        Version|        DESCRIPTION
/// ----------|-------------|---------------|-------------------
/// 2018-06-01|   zhangyanqun|          0.0.1|            created
///=================================================================================================
void REVERSAL_ORDER_IDX_hy(int n_point, int radix_array[11], int order[3240])
{
    int J[3240] = {0};
    int I, count, temp, mul, K1, K2, i, j;
    if (n_point >= radix_array[0])
    {
        J[0] = n_point / radix_array[0]; //%倒位序g进制下面的一个数是上面一个数在最高位加1，并由高位向低位进位得到
        for (I = 1; I < n_point - 2; I++) //%1st and the last don't need computing
        {
            K1 = (radix_array[0] - 1) * n_point / radix_array[0]; //%K1的最高位是g-1，其余全是0
            K2 = K1 / (radix_array[0] - 1); // %K2的最高位是1，其余全是0
            temp = J[I - 1];
            count = 0;
            mul = radix_array[0];
            while (temp >= K1) //%需要向下进位
            {
                count = count + 1; //store right shift time
                J[I] = temp - K1;
                temp = J[I];
                //%update K1 K2
                mul = mul * radix_array[count];
                K1 = (radix_array[count] - 1) * (n_point / mul);
                K2 = K1 / (radix_array[count] - 1);
            }
            J[I] = temp + K2;
        }
    }
    for (i = 0; i < n_point - 2; i++)
    {
        order[i + 1] = J[i];
    }
    order[0] = 0;
    order[n_point - 1] = n_point - 1; //order is reverse order table in research report
    memset(J, -1, sizeof(int) * 3240);
    count = 0 ;
    for (i = 0; i < n_point; i++)
    {
        for (j = 0; j < n_point; j++)
        {
            if (order[j] == i)
            {
                J[count] = j;
                count = count + 1;
                break;
            }

        }
    }
    memcpy(order, J, sizeof(int)*n_point); // order is reorder table for fpga in pipeline
}
///=================================================================================================
/// TimeDomainWindow_para_gen.
///
/// @author zhangyanqun
/// @date   2018/07/31
///
/// @param [inout] SimParam
/// @out L_w\wdn_coef Q(14,1)
/// -
///       Date|       Author|        Version|        DESCRIPTION
/// ----------|-------------|---------------|-------------------
/// 2018-06-01|   zhangyanqun|          0.0.1|            created
///=================================================================================================
void TimeDomainWindow_para_gen(stULParamTable *SimParam)
{
    fractN wdn_4096[82] = {0, 3, 12, 27, 48, 75, 108, 146, 191, 241, 297, 358, 425, 498, 575, 658, 746, 838, 936, 1038, 1145, 1256, 1371, 1490, 1613, 1739, 1870, 2003, 2139, 2279, 2420, 2565, 2711, 2860, 3011, 3163, 3316, 3471, 3626, 3782, 3939, 4096, 4253, 4410, 4566, 4721, 4876, 5029, 5181, 5332, 5481, 5627, 5772, 5913, 6053, 6189, 6322, 6453, 6579, 6702, 6821, 6936, 7047, 7154, 7256, 7354, 7446, 7534, 7617, 7694, 7767, 7834, 7895, 7951, 8001, 8046, 8084, 8117, 8144, 8165, 8180, 8189};
    fractN wdn_2048[41] = {0, 12, 48, 108, 191, 297, 425, 575, 746, 936, 1145, 1371, 1613, 1870, 2139, 2420, 2711, 3011, 3316, 3626, 3939, 4253, 4566, 4876, 5181, 5481, 5772, 6053, 6322, 6579, 6821, 7047, 7256, 7446, 7617, 7767, 7895, 8001, 8084, 8144, 8180};
    fractN wdn_1024[21] = {0, 46, 182, 406, 712, 1093, 1542, 2048, 2600, 3185, 3790, 4402, 5007, 5592, 6144, 6650, 7099, 7480, 7786, 8010, 8146};
    fractN wdn_512[11] = {0, 166, 650, 1414, 2394, 3513, 4679, 5798, 6778, 7542, 8026};
    fractN wdn_256[6] = {0, 549, 2048, 4096, 6144, 7643};
	fractN wdn_128[3] = { 0, 2048, 6144};
    int8 window_len;
    fractN *src;
    int fft_size;
    fft_size = SimParam->FftSize * 15 / (SimParam->SCS[SimParam->UeScsIdx]);
    switch (fft_size)
    {
        case 4096:
            window_len = 82;
            src = wdn_4096;
            break;
        case 2048:
            window_len = 41;
            src = wdn_2048;
            break;
        case 1024:
            window_len = 21;
            src = wdn_1024;
            break;
        case 512:
            window_len = 11;
            src = wdn_512;
            break;
        case 256:
            window_len = 6;
            src = wdn_256;
            break;
		case 128:
			window_len = 3;
			src = wdn_128;
			break;
        case 0:    //added to protect when SimParam->FftSize and SimParam->SCS are not assigned value
            break;
    }
    if (fft_size != 0)
    {
        SimParam->L_w = window_len;
        memcpy(SimParam->wdn_coef, src, sizeof(fractN)*window_len);
		for (int i = 0; i < window_len; i++)
		{
			SimParam->wdn_coef_f[i] = (double)(SimParam->wdn_coef[i] / pow(2.0, 13));
		}
    }

}
///=================================================================================================
/// PhaseCompensation_para_gen.
///
/// @author cuiyuping
/// @date   2022-06-01
///
/// @param [inout] SimParam
/// @out L_w\wdn_coef Q(14,1)
/// -
///       Date|       Author|        Version|        DESCRIPTION
/// ----------|-------------|---------------|-------------------
/// 2022-06-01|   cuiyuping |          0.0.1|            created
///=================================================================================================
void PhaseCompensation_para_gen(stULParamTable *SimParam)
{
	UINT64 ftx = SimParam->ftx; //%hz, transmission carrier frequency
	UINT32 ftxp = (UINT32)(ftx / 15000);
	double Tc = 1.0 / (480 * 1000 * 4096);  //38.211 the smallest sampling time intervel
	double Ts = 1.0 / (15 * 1000 * 2048);   //38.211 the reference sampling time intervel
	int sk = 64;                      //Ts/Tc;
	int miu = (int)(ceil(log(SimParam->SCS[SimParam->UeScsIdx] / 15 * 1.0) / log(2.0)));    //% miu = ceil(log2(SimParam.SCS_UE/15));  //consider scs=30 case
	int N_u = 2048 * sk*(int)(pow(2.0, (-miu))), iSym, i;
	double t_start[112] = { 0.0 };
	int N_CP[14] = { 0 };
	uint32 tl_fxp[112] = { 5632,75776,14848,84992,24064,94208,33280,103424,42496,112640,51712,121856,60928,0,71168,10240,80384,19456,89600,28672,98816,37888,108032,47104,117248,56320,126464,65536 };
	uint32 tl_miu, nl_p;
	uint64 mul_tmp;
	cmplx_frN w_phase_tmp[1];
	w_phase_tmp[0].re = 0;
	w_phase_tmp[0].im = 0;
	int fix_float = 0;//0--float  1--fix
	uint64 tmp = 4294967296;
	int N_Symb_Slot = (SimParam->CP_Type[SimParam->UeScsIdx] == 0) ? 14 : 12;
	uint64 n;
	int nl_p_wh[112];
	for (i = 0; i < 112; i++)
	{
		nl_p_wh[i] = 0;
	}

	if (ftx >= 24.25008e9) // 载频是60kHz倍
	{
		ftxp = ftx /(UINT64)60000; // 404168~1616666
	}
	else if (ftx >= 3.0e9) // 载频是15kHz倍
	{
		ftxp = ftx / (UINT64)15000; // 200000~1616666
	}
	else  // 载频是5kHz倍
	{
		ftxp = ftx / (UINT64)5000; // 0~599000
	}
	SimParam->slotidxfor0p5ms = SimParam->iTTI % (SimParam->SCS[SimParam->UeScsIdx] / 15);

	for (iSym = 0; iSym < N_Symb_Slot * pow(2.0, miu); iSym++)
	{
		tl_miu = t_l_u[miu][iSym]; // Q(17,17)

		if ((SimParam->CP_Type[SimParam->UeScsIdx] > 0) && (miu > 1)) // ECP
		{
			tl_miu = t_l_u_ECP[miu - 2][iSym];
		}
		else // NCP
		{
			tl_miu = t_l_u[miu][iSym];
		}

		// nl_p
		if (ftx >= 24.25008e9) // 载频是60kHz倍
		{
			mul_tmp = (uint64)(ftxp * tl_miu); // Q(35, 35)
			if (mul_tmp >= tmp)
			{
				mul_tmp = tmp - 1;//截取低32位
			}
			nl_p = (uint32)((mul_tmp % 256) * 16); // Q(12,12)
		}
		else if (ftx >= 3.0e9) // 载频是15kHz倍
		{
			mul_tmp = (uint64)(ftxp * tl_miu); // Q(35, 35)
			if (mul_tmp >= tmp)
			{
				mul_tmp = tmp - 1;//截取低32位
			}
			nl_p = (uint32)((mul_tmp % 1024) * 4); // Q(12,12)
		}
		else // 载频是5kHz倍
		{
			n = ((uint64)(ftxp) * 699051) >> 31;
			mul_tmp = ftxp - n * 3072; // Q(12, 12)
			mul_tmp = mul_tmp * tl_miu; // Q(26, 26)
			n = (mul_tmp * 699051) >> 31;
			mul_tmp = mul_tmp - n * 3072; // Q(10, 10)
			nl_p = (uint32)(mul_tmp * 43691 >> 15); // Q(12,12)
		}

		exp_1jx2xpixnvs4096_fxptable(w_phase_tmp, nl_p);
		nl_p_wh[iSym] = nl_p;

		SimParam->w_phase_fxp[iSym].re = sat_fr1xN_bitwidth(w_phase_tmp[0].re >> 2, 14);// Q(16,1)
		SimParam->w_phase_fxp[iSym].im = sat_fr1xN_bitwidth(w_phase_tmp[0].im >> 2, 14);// Q(16,1)
	}

}
//=================================================================================================
/// SRP_para_gen
/// SRP模块左移位数N_SCALE和缩放因子lamda的计算
/// @author	cuiyuping
/// @date	2018/12/25
///
/// @param [in]	       SimParam		       参数输入结构体.
/// @par History 
/// -
///       Date|       Author|        Version|        DESCRIPTION
/// ----------|-------------|---------------|-------------------
/// 2018-12-25|    cuiyuping|          0.0.1|            created
///=================================================================================================
void SRP_para_gen(INOUT  stULParamTable   *SimParam)
{
	int FFT_blk_exp = 0;
	int RBNum = 273;
	int shift_factor[6] ={0};
	int i,N_Scale,lamda_scale;
	double beta1,P_PUSCH,temp;  //beta1：符号级前端幅度缩放因子 P_PUSCH/P_SRS：SRP scaler输入的基带信号功率
	int N_Sym = 2 * (7 - SimParam->CP_Type[SimParam->UeScsIdx]);
	int SlotNum0p5 = SimParam->SCS[SimParam->UeScsIdx] / 15;
	double P_target = 0;

	FTT_para_gen(SimParam); //计算ifft shift scale

	//computing srp scaler para start refer to<<LTE 上行SRP beta因子研究报告>>
	//符号级前端幅度缩放因子beta1 
	beta1= SimParam->float_fix_dif;

	P_target = SimParam->P_target;
	//P_target = SimParam->P_target + 10 * log10(SimParam->PUSCH_RB_Num / 256.0);// 256RB对应-8dB
	//P_target = SimParam->P_target + 10 * log10(8 * SimParam->PUSCH_RB_Num) - 10 * log10(8 * 256);// 256RB对应-8dB
	P_PUSCH = SimParam->PUSCH_RB_Num*12.0*(beta1 / pow(2.0, SimParam->sum_shift + 4))*(beta1 / pow(2.0, SimParam->sum_shift + 4)); // 4是从Q(16, 5)转换为Q(16, 1)

	SRP_para_cal(P_target, P_PUSCH, &temp, &N_Scale);
	lamda_scale = (fractN)(temp*pow(2, 13));
	//打桩
	//N_Scale = 0;
	//lamda_scale = 1;
	for(i = SimParam->PUSCH_Symb_Start; i<SimParam->PUSCH_SymNum; i++)
	{
		SimParam->Lamda_Scale_flt[i].re = temp * SimParam->w_phase_fxp[(SimParam->iTTI%SlotNum0p5)*N_Sym + i].re / 8192;
		SimParam->Lamda_Scale_flt[i].im = temp * SimParam->w_phase_fxp[(SimParam->iTTI%SlotNum0p5)*N_Sym + i].im / 8192;
		SimParam->Lamda_Scale[i].re = sat_fr1xN_bitwidth(((lamda_scale*SimParam->w_phase_fxp[(SimParam->iTTI%SlotNum0p5)*N_Sym + i].re) >> 13),14);  //8192 means Q(14,1)
		SimParam->Lamda_Scale[i].im = sat_fr1xN_bitwidth(((lamda_scale*SimParam->w_phase_fxp[(SimParam->iTTI%SlotNum0p5)*N_Sym + i].im) >> 13),14);
		SimParam->n_Scale[i] = N_Scale;
	}	
}
///======================================================================
/// FTT_para_gen
/// @brief     计算FFT模块的移位因子
///
/// @param  [inout]   *SimParam       结构体参数表.
/// @note      no
/// @par History
/// -
///      Date|       Author|        Version|        DESCRIPTION
/// ----------|-------------|---------------|-------------------
/// 2018-12-08|  cuiyuping|          1.0.0|            crated
///======================================================================
void FTT_para_gen(IN stULParamTable *SimParam)
{
	int8 i;
	int shift_factor[12] = { 0 };
	int FFTSize = SimParam->FftSize * 15 / (SimParam->SCS[SimParam->UeScsIdx]);
	int8 FFT_Idx = (int8)(log2(FFTSize));

	SimParam->sum_shift = 1; // 两路累加的移位因子
	SimParam->FFT_Shift = 0;
	for (i = 0; i < 12; i++)
	{
		SimParam->ifft_shift_factor[i] = StageRightShift_SmallRB[FFT_Idx - 7][i];
		SimParam->sum_shift = SimParam->sum_shift + SimParam->ifft_shift_factor[i];
		SimParam->FFT_Shift = SimParam->FFT_Shift + SimParam->ifft_shift_factor[i] * pow(2, i);
	}
}
//=================================================================================================
/// SRP_para_cal
/// SRP模块左移位数N_SCALE和缩放因子lamda的计算
/// @author	shanshan
/// @date	2021/09/28
///
/// @param [in]	       SimParam		       参数输入结构体.
/// @par History 
/// -
///       Date|       Author|        Version|        DESCRIPTION
/// ----------|-------------|---------------|-------------------
/// 2021-09-28|     shanshan|          0.0.1|            created
///=================================================================================================
void SRP_para_cal(double P_target, double P_Base, double Lamda_Scale[1], int N_Scale[1])
{
	double P_Base_dB;  // 基带功率
	double Tmp = 0;

	P_Base_dB = 10 * log10(P_Base);
	N_Scale[0] = (int)ceil((P_target - P_Base_dB) / (20 * log10(2.0)));
	Tmp = (float)(P_target - P_Base_dB - N_Scale[0] * 20 * log10(2.0)) / 20;
	Lamda_Scale[0] = pow(10, Tmp);
}

//	%=====================================================================
//	%> @brief           定点相位补偿系数,输出exp(-1j*2*pi*n/4096)的定点值，定标Q(16,1),n=0~4095

//	%> @note            
//	%> @see calls:       
//%> @see calledby:   gnb_rx_front_m->phase_compensation_m
//	%	%> @todo            
//	%	%> @bug             
//	%> @param [in]      n
//	%> @param [out]     phasedata  
//	%> @par History
//	%> -
//	%>       Date|       Author|        Version|        DESCRIPTION
//	%> ----------|-------------|---------------|-------------------
//	%> 2019-02-19|    cuiyuping|          0.0.1|            created
//	%=====================================================================
void exp_1jx2xpixnvs4096_fxptable(cmplx_frN phasedata[1], int n)
{
	int np;	
	cmplx_frN data_table[513];
	cmplx_frN data_1;
	int i;
	for(i = 0;i<513;i++)
	{
		data_table[i].re = g_phase_compensation_re[i];
		data_table[i].im = g_phase_compensation_im[i];
	}

	if((n>=0)&&(n<=512)) 
	{
		np = n;
		data_1.re = data_table[np].re; 
		data_1.im = data_table[np].im; 
	}
	else if ((n>=513)&(n<=1023))
	{
		np = 1024-n;

		data_1.re = (-1)*data_table[np].im;
		data_1.im = (-1)*data_table[np].re;

	}
	else if (((n>=1024)&(n<=1535)))
	{
		np = n-1024;
		data_1.re =      data_table[np].im;
		data_1.im = (-1)*data_table[np].re; 
	}
	else if ((n>=1536)&(n<=2047))
	{
		np = 2048-n;
		data_1.re =  (-1)*data_table[np].re  ;
		data_1.im = data_table[np].im; 

	}
	else if ((n>=2048)&(n<=2559))
	{
		np = n-2048; 
		data_1.re = (-1)*data_table[np].re;
		data_1.im = (-1)*data_table[np].im; 
	}
	else if ((n>=2560)&(n<=3071))
	{
		np = 3072-n;
		data_1.re = data_table[np].im;
		data_1.im = data_table[np].re; 
	}
	else if ((n>=3072)&(n<=3583))
	{
		np = n-3072;
		data_1.re = (-1)*data_table[np].im;
		data_1.im = data_table[np].re; 
	}
	else if ((n>=3584)&(n<=4095))
	{
		np = 4096-n;
		data_1.re = data_table[np].re; 
		data_1.im = -data_table[np].im; 
	}


	phasedata[0].re = data_1.re ;
	phasedata[0].im = data_1.im ;

	if (phasedata[0].re >32767)
	{
		phasedata[0].re = 32767;
	}
	if (phasedata[0].im >32767)
	{
		phasedata[0].im = 32767;
	}

}
